package com.kedacom.ctsp.authority.service.simple;

import com.kedacom.ctsp.authority.entity.ChargeRelation;
import com.kedacom.ctsp.authority.entity.DataDict;
import com.kedacom.ctsp.authority.entity.SettingForType;
import com.kedacom.ctsp.authority.service.ChargeRelationService;
import com.kedacom.ctsp.authority.service.DataDictService;
import com.kedacom.ctsp.lang.RandomUtil;
import com.kedacom.ctsp.lang.StringUtil;
import com.kedacom.ctsp.lang.Validate;
import com.kedacom.ctsp.orm.dsl.Query;
import com.kedacom.ctsp.web.entity.TreeSupportBean;
import com.kedacom.ctsp.web.entity.param.QueryParamEntity;
import com.kedacom.ctsp.web.service.StatusEnum;
import com.kedacom.ctsp.web.service.simple.AbstractCrudEntityService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author sunchenjie
 * @date 2017/10/30
 */
@Service
public class ChargeRelationServiceImpl extends AbstractCrudEntityService<ChargeRelation, String>
        implements ChargeRelationService {

    @Autowired
    private DataDictService dataDictService;

    @Override
    public String insert(ChargeRelation entity) {
        if (entity.getStatus() == null) {
            entity.setStatus(StatusEnum.ENABLE.ordinal());
        }

        //添加纪录，检查被分管的节点(同一个类型，To节点，不能有多个父节点)
        insertCheckRelationTo(entity);

        entity.setStatus(StatusEnum.ENABLE.ordinal());

        //添加纪录，检查分管节点(同一个类型，From节点，不能有多个父节点)
        insertCheckRelationFrom(entity);

        //查询是否有子节点
        //多层下级
        Set<ChargeRelation> childrenTree = treeChildren(entity);

        //多层下级，不能有自己（不能形成环路）
        for (ChargeRelation chargeRelation : childrenTree) {
            if (StringUtils.equals(chargeRelation.getIdTo(), entity.getIdFrom())) {
                Validate.isTrue(false, "分管关系不能形成闭环");
            }
        }

        //更新所有
        childrenTree.stream().forEach(
                child -> {
                    child.setPath(entity.getPath() + "-" + child.getPath());
                    update(child.getId(), child);
                }
        );
        return super.insert(entity);
    }

    /**
     * 添加纪录，检查分管节点
     *
     * @param entity
     */
    private void insertCheckRelationFrom(ChargeRelation entity) {
        //查询是否有父节点，同一个类型，From节点，不能有多个父节点
        List<ChargeRelation> parent = this.createQuery().where()
                .is(ChargeRelation.CHARGE_TYPE, entity.getChargeType())
                .is(ChargeRelation.TYPE_TO, entity.getTypeFrom())
                .is(ChargeRelation.ID_TO, entity.getIdFrom()).listNoPaging();

        // parent 必须只有一个
        Validate.isTrue(parent.size() <= 1, "最多只能有一个父节点");

        // 决定当前path
        if (parent != null && parent.size() == 1) {
            entity.setPath(parent.get(0).getPath() + "-" + RandomUtil.randomString(5));
        } else {
            entity.setPath(RandomUtil.randomString(5));
        }
    }

    /**
     * 添加纪录，检查被分管的节点
     *
     * @param entity
     */
    private void insertCheckRelationTo(ChargeRelation entity) {
        //被分管的，同一个类型，To节点，不能有多个父节点
        List<ChargeRelation> results = this.createQuery().where()
                .is(ChargeRelation.CHARGE_TYPE, entity.getChargeType())
                .is(ChargeRelation.TYPE_TO, entity.getTypeTo())
                .is(ChargeRelation.ID_TO, entity.getIdTo()).listNoPaging();

        if (results.size() > 0) {

            Validate.isTrue(results.size() <= 1, "数据错误，存在多个父节点");

            // results.size == 1的情况
            ChargeRelation exist = results.get(0);
            // 如果是相同的，告诉用户已经定义过该类型
            if (exist.getIdFrom().equals(entity.getIdFrom()) && exist.getTypeFrom().equals(entity.getTypeFrom())) {
                Validate.isTrue(false, "重复数据，已经定义过该类型");
            }
            //如果不同，则不予许在一种Charge类型下，一个节点有多个父节点
            else {
                Validate.isTrue(false, "同一种分管类型下，一个节点不能有多个父节点");
            }
        }
    }

    /**
     * 直接下级
     *
     * @param entity
     * @return
     */
    private List<ChargeRelation> nextChildren(ChargeRelation entity) {
        List<ChargeRelation> children = this.createQuery().where()
                .is(ChargeRelation.CHARGE_TYPE, entity.getChargeType())
                .is(ChargeRelation.TYPE_FROM, entity.getTypeTo())
                .is(ChargeRelation.ID_FROM, entity.getIdTo()).listNoPaging();
        return children;
    }

    /**
     * 多层下级
     *
     * @param entity
     * @return
     */
    private Set<ChargeRelation> treeChildren(ChargeRelation entity) {
        List<ChargeRelation> children = nextChildren(entity);
        //多层下级
        Set<ChargeRelation> childrenTree = children.stream().map(
                child -> this.createQuery().where()
                        .like$(ChargeRelation.PATH, child.getPath()).listNoPaging())
                .flatMap(list -> list.stream())
                .collect(Collectors.toSet());
        return childrenTree;
    }

    @Override
    public int delete(String id) {
        ChargeRelation entity = get(id);
        //查询是否有子节点
        String pathLike = entity.getPath() + "-";

        Set<ChargeRelation> treeChildren = treeChildren(entity);
        treeChildren.stream().forEach(
                child -> {
                    String path = child.getPath();
                    int index = path.indexOf(pathLike);
                    if (index >= 0) {
                        String newPath = path.substring(index + pathLike.length(), path.length());
                        child.setPath(newPath);
                        update(child.getId(), child);
                    }
                }
        );
        return super.delete(id);
    }

    @Override
    public Set<String> getChargeIds(int typeFrom, String id, int typeTo) {
        List<ChargeRelation> crs = createQuery().where()
                .is(ChargeRelation.TYPE_FROM, typeFrom)
                .is(ChargeRelation.ID_FROM, id)
                .is(ChargeRelation.TYPE_TO, typeTo)
                .listNoPaging();

        if (CollectionUtils.isEmpty(crs)) {
            return new HashSet();
        }

        Query<ChargeRelation, QueryParamEntity> where = createQuery().where();

        crs.stream().forEach(cr -> where.or().like(ChargeRelation.PATH, cr.getPath()));
        List<ChargeRelation> chargeRelationEntities = where.listNoPaging();

        return chargeRelationEntities.stream().map(ChargeRelation::getIdTo).collect(Collectors.toSet());
    }


    @Override
    public Map<String, Set<String>> getCharge(String type, Set<String> ids) {
        List<ChargeRelation> crs = createQuery().where()
                .is(ChargeRelation.TYPE_FROM, type)
                .in(ChargeRelation.ID_FROM, ids)
                .listNoPaging();
        if (CollectionUtils.isNotEmpty(crs)) {
            //所有子节点,使用节点的path属性进行快速查询,查询结果包含了根节点
            List<ChargeRelation> crsCascade = createQuery()
                    //遍历生成查询条件: like path like ?||'%' or path like ?||'%'  ....
                    .each(crs, (query, data) -> query.or().like$(TreeSupportBean.PATH, data.getPath()))
                    .listNoPaging();

            Map<SettingForType, List<ChargeRelation>> collect = crsCascade.stream().collect(Collectors.groupingBy(ChargeRelation::getTypeTo));

            Map<String, Set<String>> typeIds = new HashMap<>();
            collect.entrySet().stream().forEach(typeId ->
                    typeIds.put(typeId.getKey().getValue(), typeId.getValue().stream().map(ChargeRelation::getIdTo).collect(Collectors.toSet()))
            );
            return typeIds;
        }
        return new HashMap<>(0);
    }


    @Override
    public String update(String id, ChargeRelation entity) {
        //更分管关系，只允许更新chargeType，中间操作数据较多，不直接修改分管双方信息
        ChargeRelation dataBaseChargeRelation = get(id);
        Validate.notNull(dataBaseChargeRelation, "auth.charge.relation.notexist");


        if (!StringUtils.equals(dataBaseChargeRelation.getChargeType(), entity.getChargeType())) {

            //修改了chargeType

            DataDict dataDict = dataDictService.findByCode(entity.getChargeType());
            if (dataDict == null) {
                Validate.isTrue(false, StringUtil.format("auth.charge.relation.notexist"));
            }

            //查看新类型，是否已经有该分管记录存在
            List<ChargeRelation> typeDatas = this.createQuery().where()
                    .is(ChargeRelation.CHARGE_TYPE, entity.getChargeType())
                    .is(ChargeRelation.TYPE_FROM, dataBaseChargeRelation.getTypeFrom())
                    .is(ChargeRelation.ID_FROM, dataBaseChargeRelation.getIdFrom())
                    .is(ChargeRelation.TYPE_TO, dataBaseChargeRelation.getTypeTo())
                    .is(ChargeRelation.ID_TO, dataBaseChargeRelation.getIdTo()).listNoPaging();

            if(CollectionUtils.isNotEmpty(typeDatas)){
                Validate.isTrue(false, StringUtil.format("uth.charge.relation.exist"));
            }
            //更新chargeType
            dataBaseChargeRelation.setChargeType(entity.getChargeType());

            return update(dataBaseChargeRelation);

        }


        return "";
    }
}
